#ifndef __SCHEME_H
#define __SCHEME_H



typedef enum SchemeType {
  SCHEME_VOID,
  SCHEME_INT,
  SCHEME_CHAR,
  SCHEME_BOOL,
  SCHEME_STRING,
  SCHEME_NIL,
  SCHEME_PAIR,
  SCHEME_VECTOR,
  SCHEME_SYMBOL,
  SCHEME_CLOSURE,
} SchemeType;

typedef enum BoolType {
  BOOL_TRUE,
  BOOL_FALSE,
} BoolType;

typedef struct SOBVoid {
	SchemeType type;
} SOBVoid;

typedef struct SOBNil {
	SchemeType type;
} SOBNil;

typedef struct SOBInt {
	SchemeType type;
	int value;
} SOBInt;

typedef struct SOBChar {
	SchemeType type;
	char value;
} SOBChar;

typedef struct SOBBool {
	SchemeType type;
	BoolType value;
} SOBBool;

typedef struct SOBString {
	SchemeType type;
	int length;
	char *value;
} SOBString;

typedef struct SOBPair {
	SchemeType type;
	union SchemeObject *car;
	union SchemeObject *cdr;
} SOBPair;

typedef struct SOBVector {
	SchemeType type;
	int length;
	union SchemeObject **vec;
} SOBVector;

typedef struct SOBSymbol {
	SchemeType type;
	struct SymbolEntry *sep;
} SOBSymbol;

typedef struct SOBClosure {
	SchemeType type;
	union SchemeObject ***env;
	void *code;
} SOBClosure;

typedef union SchemeObject {
	struct SOBVoid	  svod;
	struct SOBVoid	  snil;
	struct SOBInt	  sint;
	struct SOBChar	  schr;
	struct SOBBool	  sboo;
	struct SOBString  sstr;
	struct SOBPair	  spar;
	struct SOBVector  svec;
	struct SOBSymbol  ssym;
	struct SOBClosure scls;
} SchemeObject;

/* Casting macros */
#define VOID(x)		((void *) (x))
#define SOB(x)		((SchemeObject *) (x))
#define SOB_INT(x)	((SOBInt *)    (x))
#define SOB_CHR(x)	((SOBChar *)   (x))
#define SOB_BOO(x)	((SOBBool *)   (x))
#define SOB_STR(x)	((SOBString *) (x))
#define SOB_PAR(x)	((SOBPair *)   (x))
#define SOB_VEC(x)	((SOBVector *) (x))
#define SOB_SYM(x)	((SOBSymbol *) (x))
#define SOB_CLS(x)	((SOBClosure *)(x))

/* Access to type field */
#define IS_SOB_VOID(x)           (SOB((x))->svod.type == SCHEME_VOID)
#define IS_SOB_NIL(x)            (SOB((x))->snil.type == SCHEME_NIL)
#define IS_SOB_INT(x)            (SOB((x))->sint.type == SCHEME_INT)
#define IS_SOB_CHAR(x)           (SOB((x))->schr.type == SCHEME_CHAR)
#define IS_SOB_BOOL(x)           (SOB((x))->sboo.type == SCHEME_BOOL)
#define IS_SOB_STRING(x)         (SOB((x))->sstr.type == SCHEME_STRING)
#define IS_SOB_PAIR(x)           (SOB((x))->spar.type == SCHEME_PAIR)
#define IS_SOB_VECTOR(x)         (SOB((x))->svec.type == SCHEME_VECTOR)
#define IS_SOB_SYMBOL(x)         (SOB((x))->ssym.type == SCHEME_SYMBOL)
#define IS_SOB_CLOSURE(x)        (SOB((x))->scls.type == SCHEME_CLOSURE)

/* Access to object specific fields */
#define SOB_INT_VALUE(x)			SOB_INT((x))->value
#define SOB_CHAR_VALUE(x)			SOB_CHR((x))->value
#define SOB_BOOL_VALUE(x)			SOB_BOO((x))->value
#define SOB_STRING_LENGTH(x)		SOB_STR((x))->length
#define SOB_STRING_VALUE(x)			SOB_STR((x))->value
#define SOB_STRING_REF(x, i)		SOB_STRING_VALUE((x))[i]
#define SOB_STRING_SET(x, i, c)		SOB_STRING_VALUE((x))[i] = c
#define SOB_PAIR_CAR(x)				SOB_PAR((x))->car
#define SOB_PAIR_CDR(x)				SOB_PAR((x))->cdr
#define SOB_VECTOR_VALUE(x)			SOB_VEC((x))->vec
#define SOB_VECTOR_LENGTH(x, n)		SOB_VEC((x))->length
#define SOB_VECTOR_REF(x, i)		SOB_VECTOR_VALUE((x))[i]
#define SOB_VECTOR_SET(x, i, sob)	SOB_VECTOR_VALUE((x))[i] = sob
#define SOB_SYMBOL_ENTRY(x)			SOB_SYM((x))->sep
#define SOB_CLOSURE_ENV(x)			SOB_CLS((x))->env
#define SOB_CLOSURE_CODE(x)			SOB_CLS((x))->code


//SchemeObject *makeSchemeObject();
//SchemeObject *makeSchemeVoid();
//SchemeObject *makeSchemeInt(int n);
//SchemeObject *makeSchemeChar(char c);
//SchemeObject *makeSchemeBool(BoolType b);
//SchemeObject *makeSchemeString(int n, char *s);
//SchemeObject *makeSchemeStringFromCString(char *s);
//SchemeObject *makeSchemeNil();
//SchemeObject *makeSchemePair(SchemeObject *car, SchemeObject *cdr);
//SchemeObject *makeSchemeVectorInit(int n, SchemeObject *initSob);
//SchemeObject *makeSchemeSymbol(char *s);

void *autoMalloc(int size);

#define MAX_STACK_SIZE 16384

void *r0, *r1, *r2, *r3, *r4, *r5, *r6, *r7,
     *r8, *r_9, *r10, *r11, *r12, *r13, *r14, *r15,
     *r_res;
int sp, fp;
void *stack[MAX_STACK_SIZE];

#endif
